%==========================================================================
%=  This file is part of the Sound Restoration Project
%=  (c) Copyright Industrial Mathematics Institute
%=                University of South Carolina, Department of Mathematics
%=  ALL RIGHTS RESERVED
%=
%=  Author: Borislav Karaivanov
%==========================================================================

%==========================================================================
% List of the files on which this procedure depends:
%
% readImageFile.m
% readdpx.m
% Image processing toolbox
%
%==========================================================================

%==========================================================================
% The function "readImagesByIndexRange" reads in a single image file or a
% range of image files with specified prefix, index or index range, and
% extension. The file can be either in a .dpx or in any other image format
% readable by the built-in Matlab image reader.
% INPUT: "indRange" is either a single integer specifying the index of an
% image file to be read, or a pair of two integers specifying the indices
% of the first and the last image files to be read.
% "inFileNamePrefix" is a string specifying the prefix (including a full
% directory path) in the name of the image file(s) to be read.
% "indFieldLength" is an optional parameter specifying the number of digits
% used to specify the index of a image in its file name. Image indices are
% specified with leading zeros. For example, if the index field length is
% 6, then the index of image 241 is specified as 000241 in its file name.
% "inFileExt" is an optional string specifying the extension of the image
% file(s) to be read. Admissible extensions are 'dpx' and any other image
% format readable by the built-in Matlab functionality.
% "doConvertToGray" is an optional logical parameter specifying whether or
% not a grayscale version of the read image(s) is to be returned.
% OUTPUT: "imageArr" returns a 3D (in case of color output image) or 2D (in
% case of a grayscale output image) image array holding the read image or
% a grayscale version of it.
% "bitDepth" returns the number of bits used to encode each pixel value in
% any single color channel.
%==========================================================================
function [imageArr, bitDepth] = readImagesByIndexRange(indRange, ...
    inFileNamePrefix, indFieldLength, inFileExt, doConvertToGray)
% readImagesByIndexRange(3, 'C:\E\NEHScans\LibraryOfCongress\Sound Tests VARIO\VA\VARIO VA TEST\PGM\VARIO VA TEST.', 6, 'pgm', true);
% [imageArr, bitDepth] = readImagesByIndexRange([3, 8], 'C:\E\NEHScans\NEH009\DPX\NEH009_', 6, 'dpx', true);

if (nargin < 3)
    indFieldLength = 6;
end
if (nargin < 4)
    inFileExt = 'dpx';
end

%==========================================================================
% Read in the first specified image file.
%==========================================================================
% Generate the file name.
indStr = num2str(indRange(1), ['%0' num2str(indFieldLength) 'd']);
fileName = [inFileNamePrefix indStr '.' inFileExt];

% Assert that the image file exists.
assert((exist(fileName, 'file') == 2), ...
    'SoundRestoration:readImageByIndex:InFileNotExisting', ...
    ['The image file %s can not be found.\n' ...
    'A non-empty string specifying a full directory path to an existing file is needed.'], fileName);

% Read in the image file.
[imageArr, bitDepth] = readImageFile(fileName, inFileExt);

% Get the size of the read image.
sizeArr = size(imageArr);

% Convert to a grayscale image, if desired, and provided the read pixels
% have three or more components (like RGB).
if ( (nargin == 5)&&(doConvertToGray == true)&&(ndims(imageArr) == 3) )
    % Convert to grayscale.
    imageArr = rgb2gray(imageArr(:, :, 1:3));
    
    % Set a function handle to the appropriate reading function (with 
    % grayscale conversion).
    readFunctHandle = @(fileName) rgb2gray(readImageFile(fileName, inFileExt));
else
    % Set a function handle to the appropriate reading function (without
    % grayscale conversion).
    readFunctHandle = @(fileName) readImageFile(fileName, inFileExt);
end

% If just one image is to be read, then it is all done.
if (isscalar(indRange) == true)
    return;
end

%==========================================================================
% Read in the rest of the specified image files, if any.
%==========================================================================
% Temporarily store the first image already read.
tempArr = imageArr;
% Allocate memory for all frames to be read.
imageArr = tempArr(ones([sizeArr, indRange(end) - indRange(1) + 1]));
% Store the first read image file appropriately. The next two lines
% generate expression for the indices of an array of the form 
% (:, :, ..., :, 1), where the number of columns (:) may vary.
baseIndCellArr = repmat({':'}, 1, ndims(tempArr));
indCellArr = [baseIndCellArr, {1}];
imageArr(indCellArr{:}) = tempArr;

frameInd = 1;
for fileInd  = (indRange(1) + 1):indRange(end)
    % Generate the file name.
    indStr = num2str(fileInd, ['%0' num2str(indFieldLength) 'd']);
    fileName = [inFileNamePrefix indStr '.' inFileExt];
    
    % Assert that the image file exists.
    assert((exist(fileName, 'file') == 2), ...
        'SoundRestoration:readImagesByIndexRange:InFileInexisting', ...
        ['The image file %s can not be found.\n' ...
        'A non-empty string specifying a full directory path to an existing file is needed.'], fileName);
    
    % Read in the image file.
    frameInd = frameInd + 1;
    indCellArr = [baseIndCellArr, {frameInd}];
    imageArr(indCellArr{:}) = readFunctHandle(fileName);
end

return;
% end of the function "readImagesByIndexRange"
